#ifndef CVALGEDGEDETECTION_H
#define CVALGEDGEDETECTION_H

#include "cvalgorithm.h"
#include "imagerecord.h"
#include "source/identifiimg.h"
#include "source/quicktool.h"
#include "source/resdiff.h"
#include "AutoPropertyHelper.h"
#include "quicktool.h"
#include <opencv2/opencv.hpp>
#include <iostream>
#include <QMap>
#include <QString>
#include <QDebug>
#include <qreadwritelock.h>
#include "autoSettinghelp.h"


class CvAlgEdgeDetection :public CVAlgorithm
{
    Q_OBJECT
    Q_PROPERTY(bool boundaryExtractionAuto READ boundaryExtractionAuto WRITE setboundaryExtractionAuto NOTIFY boundaryExtractionAutoChange)
    Q_PROPERTY(int boundaryExtraction1 READ boundaryExtraction1 WRITE setboundaryExtraction1 NOTIFY boundaryExtraction1Change)
    Q_PROPERTY(int boundaryExtraction2 READ boundaryExtraction2 WRITE setBoundaryExtraction2 NOTIFY boundaryExtraction2Change)
    Q_PROPERTY(int boundaryThreshold READ boundaryThreshold WRITE setBoundaryThreshold NOTIFY boundaryThresholdChange)
    Q_PROPERTY(CVSelectionEnum cvSelection READ cvSelection WRITE setcvSelection NOTIFY cvSelectionChanged )
    Q_PROPERTY(int curentBoundaryValue READ curentBoundaryValue NOTIFY curentBoundaryValueChanged )
    Q_PROPERTY(float largeSmallUpperMax READ largeSmallUpperMax WRITE setlargeSmallUpperMax NOTIFY largeSmallUpperMaxChanged )
    Q_PROPERTY(float largeSmallUpperMin READ largeSmallUpperMin WRITE setlargeSmallUpperMin NOTIFY largeSmallUpperMinChanged )
    Q_PROPERTY(float largeSmallLowerMax READ largeSmallLowerMax WRITE setlargeSmallLowerMax NOTIFY largeSmallLowerMaxChanged )
    Q_PROPERTY(float largeSmallLowerMin READ largeSmallLowerMin WRITE setlargeSmallLowerMin NOTIFY largeSmallLowerMinChanged )
    Q_PROPERTY(float LargeSmallLastTop READ LargeSmallLastTop WRITE setLargeSmallLastTop NOTIFY LargeSmallLastTopChanged )
    Q_PROPERTY(float LargeSmallLastBottom READ LargeSmallLastBottom WRITE setLargeSmallLastBottom NOTIFY LargeSmallLastBottomChanged )

    Q_PROPERTY(float resthreshold READ resthreshold WRITE setresthreshold NOTIFY resthresholdChanged )
    Q_PROPERTY(float currentpredscore READ currentpredscore NOTIFY currentpredscoreChanged )

    Q_PROPERTY(int edgeSmoothing READ edgeSmoothing WRITE setedgeSmoothing NOTIFY edgeSmoothingChanged )
    Q_PROPERTY(int overturn READ overturn WRITE setoverturn NOTIFY overturnchanged)
    Q_PROPERTY(int isInit READ isInit  NOTIFY isInitchanged)

public:
    enum CVSelectionEnum{
        EdgeDetection,
        LargeAsmallDetection,
        characterEmphasis,
        TiltDetection,
        LengthDetection,
        SpecialDiagnosis,
        SpecialDiagnosisV2,
        LogoSize,
    }CVselection;


    //特征差异V2
    GLOBAL_QML_STATE_PROPERTY(bool , isSpecialDiagnosisV2 , false)
    GLOBAL_QML_STATE_PROPERTY(int , isSpecialV2Detection , 125)
    GLOBAL_QML_STATE_PROPERTY(int , isSpecialV2redundancy , 5)
    GLOBAL_QML_STATE_PROPERTY(int , isSpecialV2median , 31)
    GLOBAL_QML_STATE_PROPERTY(float , isSpecialV2Scale , 0.5)
    GLOBAL_QML_STATE_PROPERTY(int , isSpecialV2orbNum , 500)

    GLOBAL_QML_STATE_PROPERTY(int , isSpecialV2orbCanny1 , 50)
    GLOBAL_QML_STATE_PROPERTY(int , isSpecialV2orbCanny2 , 150)

    Q_INVOKABLE void addSpecialV2base();
    Q_INVOKABLE void resetSpecialV2base();
    Q_INVOKABLE void enbaleSpecialV2(); //启用
    Q_INVOKABLE void setEdegCany();
    Q_INVOKABLE void setSpecialV2Roi(int x ,int y, int wid, int hei);
    Q_INVOKABLE void resetSpecialV2Roi();
    cv::Rect specialRoi;

    cv::Mat specialGetedgeCanny(cv::Mat image, int thread1, int thread2);
    cv::Mat getSpecialDiff(cv::Mat awaitImage);
    void addSpecialV2baseMat(cv::Mat awaitImage);
    cv::Mat specialV2BaseMatGray;
    cv::Mat specialV2BaseMat;
    cv::Mat specialV2BaseBac;
    cv::Mat specialV2BaseEdge;
    QReadWriteLock  specialV2mutex;


    AUTO_SETTING_PROPERTY(CvAlgEdgeDetection , double, px2mm, 1.0f)
    Q_INVOKABLE void autoDetectReset();

    Q_INVOKABLE void setLargeSmallTotal(double diifNum);
    Q_INVOKABLE void calibrationPx2MM();

    Q_INVOKABLE int setembedding();
    Q_INVOKABLE int loadResDiffModel();
    Q_INVOKABLE void setTotalLengthDistance(double std , double total);

    Q_INVOKABLE void setTotaltiltAngle(float total);

    Q_INVOKABLE void addEmphasize(int x,int y,int wid,int hei); //增加情调区
    Q_INVOKABLE void delEmphasize(int index); //删除情调区

    Q_INVOKABLE void setLengthROI(int x,int y,int wid,int hei); //增加情调区
    Q_INVOKABLE void resetLengthROI();

    GLOBAL_QML_STATE_PROPERTY(double,lengthDistance,0)
    GLOBAL_QML_STATE_PROPERTY(float,tiltAngle,0)

    //分码
    Q_INVOKABLE void setlogoSizeROI(int x,int y,int wid,int hei); //分码ROI
    Q_INVOKABLE void restlogoSize(); //分码ROI
    Q_INVOKABLE void testlogoSize(); //分码ROI
    //GLOBAL_QML_STATE_PROPERTY(int,emphasizeErode,3) //强调区滤波 1 3 5 7 9
    //GLOBAL_QML_STATE_PROPERTY(int,emphasizeOpen,3) //强调区其二次滤波 1 3 5 7 9
    //GLOBAL_QML_STATE_PROPERTY(int,emphasizethreshold,9) //强调区检测阈值 1-20

    //GLOBAL_QML_STATE_PROPERTY(bool,emphasizeEnable,true) //强调区列表

    GLOBAL_QML_STATE_PROPERTY(int , emphasizeIndex , 0)
    GLOBAL_QML_STATE_PROPERTY(QVariantList,emphasizeAreaList,{}) //强调区列表
    GLOBAL_QML_STATE_PROPERTY(int,emphasizeMaxarea,0) //强调区当前值

    // Q_INVOKABLE void emphasizeBinaryByIndex(int index, int binary);
    GLOBAL_QML_STATE_PROPERTY(QVariantList, emphasizeBinaryList, {}) //二值化
    GLOBAL_QML_STATE_PROPERTY(QVariantList, emphasizeBinaryliserveList, {})

    Q_INVOKABLE void lenthTest(int isShow);

    Q_INVOKABLE void emphasizeBinaryTest();
    Q_INVOKABLE void addCurentemphasizemaxBlend();
    Q_INVOKABLE void addCurentemphasizemaxBlendByCache(int id);

    Q_INVOKABLE void characterDefectTraining() ;//自动模式字符缺陷训练
    int currentProcess = 0;
    bool logosizeisTrain = false;
    bool dualisTrain = false;
    Q_INVOKABLE void addCurentemphasizemaxBlendByAuto(bool isDefect);
    //GLOBAL_QML_STATE_PROPERTY(int,emphasizeRecthreshold,30) //强调区识别阈值 0-255


    //分码
    OR_QML_STATE_PROPERTY(double, widthHeightRatioDiff ,0.0)
    OR_QML_STATE_PROPERTY(double, shapeSimilarity ,0.0)
    OR_QML_STATE_PROPERTY(double, overlapRatio ,0.0)
    AUTO_CONFIG_PROPERTY(CvAlgEdgeDetection,"cvInspection", int,  logoSizeBinary)
    AUTO_CONFIG_PROPERTY(CvAlgEdgeDetection,"cvInspection", bool, logoSizeRefuelling)
    AUTO_CONFIG_PROPERTY(CvAlgEdgeDetection,"cvInspection", bool, logoSizeisFlip)
    AUTO_CONFIG_PROPERTY(CvAlgEdgeDetection,"cvInspection", int, logoSizeRedundancy)
    AUTO_CONFIG_PROPERTY(CvAlgEdgeDetection,"cvInspection", int, logoSizethreshold)
    AUTO_CONFIG_PROPERTY(CvAlgEdgeDetection,"cvInspection", int, logoSizeContinuous)
    RW_STATE_PROPERTY(int , logoSizeErrNum ,0)
    RW_STATE_PROPERTY(int , logoSizeErrid , -1)
    RW_STATE_PROPERTY(int , logoSizedualErrid , -1)
    RW_STATE_PROPERTY(bool , logoSizeGone , false)
    RW_STATE_PROPERTY(QVector<int> , logoSizeErridList ,QVector<int>())

    AUTO_CONFIG_PROPERTY(CvAlgEdgeDetection,"cvInspection", float , logoSizetolerance)
    AUTO_CONFIG_PROPERTY(CvAlgEdgeDetection,"cvInspection", float , logoSizeshapeTolerance)
    AUTO_CONFIG_PROPERTY(CvAlgEdgeDetection,"cvInspection", float , logoSizeoverlapThreshold)


    AUTO_CONFIG_PROPERTY(CvAlgEdgeDetection,"cvInspection", int, emphasizeMode)
    AUTO_CONFIG_PROPERTY(CvAlgEdgeDetection,"cvInspection", int, emphasizeBinaryfilter)
    AUTO_CONFIG_PROPERTY(CvAlgEdgeDetection,"cvInspection", int, emphasizeBinaryKernel)
    AUTO_CONFIG_PROPERTY(CvAlgEdgeDetection,"cvInspection", bool, emphasizeBinaryliserve)

    AUTO_CONFIG_PROPERTY(CvAlgEdgeDetection,"cvInspection", QVariantList, LengthROI)
    AUTO_CONFIG_PROPERTY(CvAlgEdgeDetection,"cvInspection", int, lengthRedundancy)

    AUTO_CONFIG_PROPERTY(CvAlgEdgeDetection,"cvInspection",bool,hvdirections)
    AUTO_CONFIG_PROPERTY(CvAlgEdgeDetection,"cvInspection",bool,gradientVariation)
    AUTO_CONFIG_PROPERTY(CvAlgEdgeDetection,"cvInspection",int,alignmentRange)
    AUTO_CONFIG_PROPERTY(CvAlgEdgeDetection,"cvInspection",bool,perspectiveAlignment)

    AUTO_CONFIG_PROPERTY(CvAlgEdgeDetection,"cvInspection",int,emphasizeErode)
    AUTO_CONFIG_PROPERTY(CvAlgEdgeDetection,"cvInspection",int,emphasizeOpen)
    AUTO_CONFIG_PROPERTY(CvAlgEdgeDetection,"cvInspection",int,emphasizethreshold)

    AUTO_CONFIG_PROPERTY(CvAlgEdgeDetection,"cvInspection",bool,largeSmallEnable)
    //启动
    OR_QML_STATE_PROPERTY(bool , logoSizeEnable, false);
    GLOBAL_QML_STATE_PROPERTY(bool, diffEable, false);
    AUTO_CONFIG_PROPERTY(CvAlgEdgeDetection,"cvInspection",bool,emphasizeEnable)
    AUTO_CONFIG_PROPERTY(CvAlgEdgeDetection,"cvInspection",int,emphasizeRecthreshold)



    AUTO_CONFIG_PROPERTY(CvAlgEdgeDetection,"cvInspection",bool,lengthDetectionEnable)
    AUTO_CONFIG_PROPERTY(CvAlgEdgeDetection,"cvInspection",float,lengthDetectionThreshold)
    AUTO_CONFIG_PROPERTY(CvAlgEdgeDetection,"cvInspection",float,lengthDetectionThresholdRight)
    AUTO_CONFIG_PROPERTY(CvAlgEdgeDetection,"cvInspection",double,lengthDetectionMax)
    AUTO_CONFIG_PROPERTY(CvAlgEdgeDetection,"cvInspection",double,lengthDetectionMin)
    AUTO_CONFIG_PROPERTY(CvAlgEdgeDetection,"cvInspection",double,lengthStd)
    AUTO_CONFIG_PROPERTY(CvAlgEdgeDetection,"cvInspection",double,lengthRance)
    //启动
    AUTO_CONFIG_PROPERTY(CvAlgEdgeDetection,"cvInspection",bool,tiltAngleEnable)
    AUTO_CONFIG_PROPERTY(CvAlgEdgeDetection,"cvInspection",float,tiltAngleMax)
    AUTO_CONFIG_PROPERTY(CvAlgEdgeDetection,"cvInspection",float,tiltAngleMin)

    AUTO_CONFIG_PROPERTY(CvAlgEdgeDetection,"cvInspection",bool,edgeEnable)

    static  CvAlgEdgeDetection &getInstance();

    void initialize()  override;
    bool process(ImageRecord &imgcard) override ;
    QString getName() const override;

    int boundaryExtraction1() const {return boundaryExtraction1_;};
    void setboundaryExtraction1(int boundaryExtraction1);

    int boundaryExtraction2() const { return boundaryExtraction2_; }
    void setBoundaryExtraction2(int boundaryExtraction2);

    int boundaryThreshold() const { return boundaryThreshold_; }
    void setBoundaryThreshold(int boundaryThreshold);

    CVSelectionEnum cvSelection() const {return cvSelection_;};
    void setcvSelection(CVSelectionEnum cvSelectlargeSmallUpperMax_ion);

    int curentBoundaryValue() const {return curentBoundaryValue_;};
    void changecurentBoundaryValue(int curentBoundaryValue);

    bool boundaryExtractionAuto() const {return boundaryExtractionAuto_;};
    void setboundaryExtractionAuto(bool boundaryExtractionAuto);

    float LargeSmallLastTop() const {return LargeSmallLastTop_;};
    float LargeSmallLastBottom() const {return LargeSmallLastBottom_;};
    void setLargeSmallLastTop(float setLargeSmallLastTop);
    void setLargeSmallLastBottom(float LargeSmallLastBottom);

    float resthreshold() const {return resthreshold_;};
    void setresthreshold(float resthreshold);

    int overturn() const {return overturn_;};
    void setoverturn(int overturn);
    int edgeSmoothing() const {return edgeSmoothing_;};
    void setedgeSmoothing(int edgeSmoothing);

    int isInit() const{return resdiff.isInit;};

    float currentpredscore() const {return pred_score_;};

    void testBoundaryExtraction1(bool isAuto);
    float largeSmallUpperMax() const {return largeSmallUpperMax_;};
    void setlargeSmallUpperMax(float largeSmallUpperMax);
    float largeSmallUpperMin() const {return largeSmallUpperMin_;};
    void setlargeSmallUpperMin(float largeSmallUpperMin);
    float largeSmallLowerMax() const {return largeSmallLowerMax_;};
    void setlargeSmallLowerMax(float largeSmallLowerMax);
    float largeSmallLowerMin() const {return largeSmallLowerMin_;};
    void setlargeSmallLowerMin(float largeSmallLowerMin);

    static void detectEdgeDefects(const cv::Mat &image, int maxDeviation,
                                  std::vector<cv::Point> &defects,
                                  std::vector<cv::Point> &topPoints,
                                  std::vector<cv::Point> &bottomPoints,
                                  cv::Vec4f &topFitLine, cv::Vec4f &bottomFitLine,
                                  double &topdiff, double &bottomdiff);

    void counttiltAngle(const cv::Mat &daryimg);
    bool trainEmphasizeMaxBlend(QVector<cv::Mat> ImageList);
    bool recognizeEmphasizeMaxBlend(QVector<cv::Mat> ImageList ,
                                    QVector<QPoint> ImagePointList ,
                                    cv::Mat &draw);
    bool logoSizeisSameStyle(cv::Mat binaryImage1, cv::Mat binaryImage2, cv::Mat &out, cv::Rect Box);
signals:
    void characterDefectTrainingFinishSignal(); //完成

    void largeSmallUpperMaxChanged();
    void largeSmallUpperMinChanged();
    void largeSmallLowerMaxChanged();
    void largeSmallLowerMinChanged();

    void boundaryExtractionAutoChange();

    void curentBoundaryValueChanged();
    void boundaryExtraction1Change();
    void boundaryExtraction2Change();
    void boundaryThresholdChange();
    void cvSelectionChanged();

    void LargeSmallLastTopChanged();
    void LargeSmallLastBottomChanged();

    void resthresholdChanged();
    void currentpredscoreChanged();

    void edgeSmoothingChanged();
    void overturnchanged();
    void isInitchanged();



public slots:
    void monitorImgChangeSlots(cv::Mat& img) override;
    void configDataChanged(const QString &category, const QString &key);
    void valueTableLoad();

private:
    QAtomicInt isThreadRunning; // 原子变量，避免多线程冲突
    QMutex lenthmutex;
    QMutex logoSizeMutex;
    QMutex emphasmutex;
    QMutex resDiffMutex;

    QSettings setting;

    bool logoSizeTrrige = false;

    float pred_score_;

    float largeSmallUpperMax_;
    float largeSmallUpperMin_;
    float largeSmallLowerMax_;
    float largeSmallLowerMin_;

    float LargeSmallLastTop_;
    float LargeSmallLastBottom_;


    float saveLargeSmallLastTop_ = 0;
    float saveLargeSmallLastBottom_ = 0;
    float saveTiltAngle_ = 0;
    float currenttiltAngle_ = 0;

    float resthreshold_;

    int manualThresholdboundaryExtraction1_;
    int boundaryExtraction1_;
    int boundaryExtraction2_;
    int boundaryThreshold_;
    int curentBoundaryValue_;

    int edgeSmoothing_;
    int overturn_;

    int subdiffChart(cv::Mat &detect,cv::Mat &base,
                     cv::Mat &imageRoteDraw, int &emphasizeMax,
                     cv::Mat &emphaseShowImage,cv::Mat &emphaseShowImage2);


    bool boundaryExtractionAuto_;
    CVSelectionEnum cvSelection_;
    cv::Rect2d monitorRectCache;
    QVariantList binarayMethonName;
    QVector<cv::Mat> emphaseImageLast;
    QVector<cv::Mat> emphasizeImgaeList;
    QVector<cv::Mat> emphasizeImgaeListLast;
    QVector<cv::Mat> emPhasizeBinaryList;
    double saveLengthDistance = 0;

    //分码
    IdentifiImg logoSizeBase;
    cv::Mat logoSizeBinaryBase;
    cv::Mat extractLogoSizeFeatures(cv::Mat greayImage ,
                                    IdentifiImg &logosize ,
                                    cv::Rect &boundingBox , bool isShow = false);

    bool logoSizeisSameStyle(cv::Mat curBinary, cv::Mat baseBinary, cv::Rect curBox, cv::Rect baseBox,
                             double& widthHeightRatioDiff, double& shapeSimilarity, double& overlapRatio,
                             double tolerance = 0.1,
                             double shapeTolerance = 0.1,
                             double overlapThreshold = 0.8);


    resDiff resdiff;
    cv::Mat LastbaseImage;
    cv::Mat imgCapcache;
    cv::Mat imageRoteBase;
    CvAlgEdgeDetection(QObject *parent = nullptr);
    CvAlgEdgeDetection& operator=(const CvAlgEdgeDetection& rhs) = delete;
    cv::Mat cropBoundaryAndAdjustROI(const cv::Mat &image, cv::Rect roi);
    cv::Mat binarizeImage(const cv::Mat &image, int manualThreshold , bool isAuto  = false);
    cv::Mat edgeDetectionAndBinarize(const cv::Mat &image, int lowThreshold, int highThreshold);
    cv::Mat reverseImageIfNeeded(const cv::Mat &inputImage);
    QMap<QString, float> baselineColorRatios;  // key: colorName, value: baseline_ratio

    // 颜色范围定义

    std::vector<std::pair<std::string, std::pair<cv::Scalar, cv::Scalar>>> colorRanges ;
    void resetEmPhasizeBinaryList();
    cv::Mat emphasePreprocess(cv::Mat image , cv::Mat imageBase , bool isShowMain = false);
    void drawFitLine(cv::Mat &image, const cv::Vec4f &line, const cv::Scalar &color, int offsety = 0);
    double pointToLineDistance(const cv::Point2d &pt, const cv::Vec4f &line);
    void offsetLineY(cv::Vec4f &line, int offsety);
    cv::Mat preprocessImage(const cv::Mat &imgCapGray, const cv::Rect2d &monitorRect);
    void drawDefectsAndEdges(cv::Mat &imgCapDraw, const std::vector<cv::Point> &defects, const std::vector<cv::Point> &topPoints, const std::vector<cv::Point> &bottomPoints, const cv::Vec4f &topFitLine, const cv::Vec4f &bottomFitLine, bool isDrawOutput, const cv::Rect2d &monitorRect);
    void processROI(cv::Mat &imgDraw, ImageRecord &imgcard, cv::Vec4f &topFitLine,
                    cv::Vec4f &bottomFitLine, const cv::Rect2d &monitorRect,
                    float topMax = 0 , float topmin  = 0,
                    float btmmax  = 0, float btmMin  = 0, bool isText = false);
    void drawLine(cv::Mat &img, const cv::Vec4f &line, const cv::Scalar &color ,  int thickness = 2);
    void drawDistanceLine(cv::Mat &img, const cv::Point2d &roiCenter, const cv::Vec4f &line, double distance);
    void drawText(cv::Mat &img, const std::string &text, const cv::Point &org);
    void emphasizeprocessImage(const cv::Mat& inputImage, cv::Mat& outputImage,
                               int emphasizeThreshold, bool isInvert = false);
    void compareColorChange(const cv::Mat& baselineImg, const cv::Mat& testImg) ;
    void loadBaselineColorRatios(const cv::Mat& baselineImg, const cv::Mat& baselineHSV);
    float calculateColorPercentage(const cv::Mat& img, const cv::Mat& hsv_img, cv::Scalar lower, cv::Scalar upper);
    //cv::Mat alignImages(const cv::Mat& image1, const cv::Mat& base);
    cv::Mat getHomographyMatrix(const cv::Mat& image1, const cv::Mat& base);
};

#endif // CVALGEDGEDETECTION_H
